using Dapper;
using MediatR;
using Microsoft.EntityFrameworkCore;
using RBAC.ErrorCode;
using RBAC.Interstructrue;
using RBAC.Interstructrue.Base;
using RBAC.Write.Api.Application.Command.ERP.SalesManagement.Billing;
using System.Data;

namespace RBAC.Write.Api.Application.Handler.ERP.SalesManagement.Billing
{
    /// <summary>
    /// 更新开票通知单处理器
    /// </summary>
    public class UpdateBillingNoticeHandler : IRequestHandler<UpdateBillingNoticeCommand, APIResult<int>>
    {
        private readonly IDbConnectionFactory _dbConnectionFactory;
        private readonly RBACDbContext _context;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dbConnectionFactory">数据库连接工厂</param>
        /// <param name="context">数据库上下文</param>
        public UpdateBillingNoticeHandler(IDbConnectionFactory dbConnectionFactory, RBACDbContext context)
        {
            _dbConnectionFactory = dbConnectionFactory;
            _context = context;
        }

        /// <summary>
        /// 处理更新开票通知单请求
        /// </summary>
        /// <param name="request">更新命令</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>更新结果</returns>
        public async Task<APIResult<int>> Handle(UpdateBillingNoticeCommand request, CancellationToken cancellationToken)
        {
            IDbConnection connection = null;
            IDbTransaction transaction = null;

            try
            {
                // 查找要更新的开票通知单
                var billingNotice = await _context.BillingAccountings
                    .Include(b => b.BillingMaterials)
                    .FirstOrDefaultAsync(b => b.Id == request.Id && !b.IsDeleted, cancellationToken);

                if (billingNotice == null)
                {
                    return new APIResult<int>
                    {
                        Code = APIEnums.Fail,
                        Msg = "未找到指定的开票通知单"
                    };
                }

                // 创建数据库连接
                connection = _dbConnectionFactory.CreateConnection();

                // 开始事务
                transaction = connection.BeginTransaction();

                // 1. 更新开票通知单主表
                await UpdateBillingNoticeAsync(connection, transaction, request);

                // 2. 处理开票物料明细（更新、新增、删除）
                await ProcessBillingMaterialsAsync(connection, transaction, request);

                // 3. 提交事务
                transaction.Commit();

                return new APIResult<int>
                {
                    Code = APIEnums.Success,
                    Msg = "开票通知单更新成功",
                    Data = 1
                };
            }
            catch (Exception ex)
            {
                // 回滚事务
                if (transaction != null)
                {
                    try
                    {
                        transaction.Rollback();
                    }
                    catch (Exception rollbackEx)
                    {
                        // 记录回滚异常
                        Console.WriteLine($"事务回滚失败: {rollbackEx.Message}");
                    }
                }

                return new APIResult<int>
                {
                    Code = APIEnums.Fail,
                    Msg = "更新开票通知单失败：" + ex.Message,
                    Data = 0
                };
            }
            finally
            {
                // 确保连接被正确关闭
                if (connection != null && connection.State != ConnectionState.Closed)
                {
                    connection.Close();
                }
            }
        }

        /// <summary>
        /// 更新开票通知单主表
        /// </summary>
        /// <param name="connection">数据库连接</param>
        /// <param name="transaction">事务</param>
        /// <param name="request">更新请求</param>
        /// <returns></returns>
        private async Task UpdateBillingNoticeAsync(
            IDbConnection connection,
            IDbTransaction transaction,
            UpdateBillingNoticeCommand request)
        {
            var sql = @"
                UPDATE BillingAccounting 
                SET 
                    BusinessType = @BusinessType,
                    CustomerName = @CustomerName,
                    BankName = @BankName,
                    ProductCode = @AccountNumber,
                    DeliveryEmail = @DeliveryEmail,
                    BillDate = @BillDate,
                    Operator = @Operator,
                    InvoiceType = @InvoiceType,
                    TaxId = @TaxNumber,
                    AddressPhone = @AddressPhone,
                    Remarks = @Remarks,
                    Status = @Status,
                    BusinessStatus = @BusinessStatus,
                    BillStatus = @BillStatus
                WHERE Id = @Id";

            // 根据状态值映射为中文状态
            string billStatusText = request.Status switch
            {
                0 => "开立",
                1 => "审核",
                2 => "退回",
                _ => "开立"
            };

            var parameters = new
            {
                request.Id,
                request.BusinessType,
                request.CustomerName,
                request.BankName,
                AccountNumber = request.AccountNumber,
                request.DeliveryEmail,
                request.BillDate,
                Operator = request.Operator ?? "System",
                request.InvoiceType,
                TaxNumber = request.TaxNumber,
                request.AddressPhone,
                request.Remarks,
                request.Status,
                request.BusinessStatus,
                BillStatus = billStatusText
            };

            await connection.ExecuteAsync(sql, parameters, transaction);
        }

        /// <summary>
        /// 处理开票物料明细（更新、新增、删除）
        /// </summary>
        /// <param name="connection">数据库连接</param>
        /// <param name="transaction">事务</param>
        /// <param name="request">更新请求</param>
        /// <returns></returns>
        private async Task ProcessBillingMaterialsAsync(
            IDbConnection connection,
            IDbTransaction transaction,
            UpdateBillingNoticeCommand request)
        {
            // 1. 处理需要删除的物料明细
            var deleteSql = "DELETE FROM BillingMaterials WHERE BillingAccountingId = @BillingAccountingId AND Id IN @Ids";
            var deleteIds = request.Items.Where(i => i.IsDeleted && i.Id.HasValue).Select(i => i.Id).ToList();
            if (deleteIds.Any())
            {
                await connection.ExecuteAsync(deleteSql, new { BillingAccountingId = request.Id, Ids = deleteIds }, transaction);
            }

            // 2. 处理需要更新的物料明细
            var updateSql = @"
                UPDATE BillingMaterials 
                SET 
                    OrderNumber = @OrderNumber,
                    MaterialCode = @MaterialCode,
                    MaterialName = @MaterialName,
                    Unit = @Unit,
                    Quantity = @Quantity,
                    UnitPrice = @UnitPrice,
                    Amount = @Amount,
                    InvoiceName = @InvoiceName,
                    Remarks = @Remarks
                WHERE Id = @Id AND BillingAccountingId = @BillingAccountingId";

            var updateItems = request.Items.Where(i => i.Id.HasValue && !i.IsDeleted).ToList();
            foreach (var item in updateItems)
            {
                var parameters = new
                {
                    item.Id,
                    BillingAccountingId = request.Id,
                    item.OrderNumber,
                    item.MaterialCode,
                    item.MaterialName,
                    item.Unit,
                    item.Quantity,
                    item.UnitPrice,
                    item.Amount,
                    item.InvoiceName,
                    item.Remarks
                };

                await connection.ExecuteAsync(updateSql, parameters, transaction);
            }

            // 3. 处理需要新增的物料明细
            var insertSql = @"
                INSERT INTO BillingMaterials (
                    OrderNumber, MaterialCode, MaterialName, Unit, Quantity, 
                    UnitPrice, Amount, InvoiceName, Remarks, 
                    BillingAccountingId, CreateTime, CreateUser, IsDeleted
                ) VALUES (
                    @OrderNumber, @MaterialCode, @MaterialName, @Unit, @Quantity,
                    @UnitPrice, @Amount, @InvoiceName, @Remarks,
                    @BillingAccountingId, @CreateTime, @CreateUser, @IsDeleted
                )";

            var insertItems = request.Items.Where(i => !i.Id.HasValue && !i.IsDeleted).ToList();
            foreach (var item in insertItems)
            {
                var parameters = new
                {
                    item.OrderNumber,
                    item.MaterialCode,
                    item.MaterialName,
                    item.Unit,
                    item.Quantity,
                    item.UnitPrice,
                    item.Amount,
                    item.InvoiceName,
                    item.Remarks,
                    BillingAccountingId = request.Id,
                    CreateTime = DateTime.Now,
                    CreateUser = "admin",
                    IsDeleted = false
                };

                await connection.ExecuteAsync(insertSql, parameters, transaction);
            }
        }
    }
}